#include  "semaphor.h"
#include  "doxon.h"
#include  "pcb.h"
#include  "schedule.h"

Semaphore::Semaphore(int init) {
    lock();
    myImpl = new KernelSem(init);
    unlock();
}

Semaphore::~Semaphore() {
    lock();
    delete myImpl;
    unlock();
}

int Semaphore::val() const {
    int tmp;

    lock();
    tmp = myImpl->value();
    unlock();
    return tmp;
}

int Semaphore::wait(Time time) {
    int tmp_return;
    lock();

    if ( myImpl->value() <= 0 ) {
        /* sa ubacivanje u queue takodje i smanjujemo vrednost semafora */
        myImpl->wait4sem.put( (PCB*)Doxon::running );
        Doxon::running->state       = PCB::BLOCKED;
        Doxon::running->time_wait   = time;
        /* Koristimo isti counter kao i za preempting... */
        Doxon::running->time_passed = 0;
        /* kernel semaphor koji poseduje ovu nit */
        Doxon::running->kern_sem_own = myImpl;
    }
    else {
        myImpl->semaphor_val --;
    }

    if (Doxon::running->state == PCB::BLOCKED || semPreempt)
        Doxon::dispatch();

    tmp_return = Doxon::running->wait_return;
    /* Resetovanje je obavezno, da bi i sledeci put wait funkcija vratila tacnu
     * vrednost */
    Doxon::running->wait_return = 0;

    unlock();

    return tmp_return;
}

void Semaphore::signal() {
    PCB* tmp;
    lock();
    if (myImpl->wait4sem.size() > 0) {
        tmp = myImpl->wait4sem.get();
        tmp->state = PCB::READY;
        /* Znaci da je odblokirana sa signal */
        tmp->wait_return = 0;
        Scheduler::put(tmp);
    }
    else {
        myImpl->semaphor_val ++;
    }

    if ( semPreempt )
        Doxon::dispatch();
    unlock();

}
